/* * Copyright 2015 McDowell * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package uk.kludje.experimental.collect; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.Objects; import java.util.function.*; /** * Adapts other types/functional interfaces to {@link java.util.Iterator} instances. */ public final class LambdaIterators { private static final Iterator<Object> EMPTY = arrayIterator(); private LambdaIterators() { } /** * Provides an {@link java.util.Iterator} backed by functional interfaces. * {@link java.util.Iterator#remove} is not supported. * * @param hasNext used to implement {@link java.util.Iterator#hasNext()} * @param next used to implement {@link java.util.Iterator#next()} * @param <E> the generic type * @return a new instance */ public static <E> Iterator<E> iterator(BooleanSupplier hasNext, Supplier<E> next) { Objects.requireNonNull(hasNext, "hasNext"); Objects.requireNonNull(next, "next"); class LambdaIterator extends BaseIterator<E> { @Override public boolean hasNext() { return hasNext.getAsBoolean(); } @Override protected E nextElement() { return next.get(); } } return new LambdaIterator(); } /** * As {@link #iterator(java.util.function.BooleanSupplier, java.util.function.Supplier)} but with remove support. * * @param hasNext used to implement {@link java.util.Iterator#hasNext()} * @param next used to implement {@link java.util.Iterator#next()} * @param remove used to implement {@link java.util.Iterator#remove()} * @param <E> the generic type * @return a new instance */ public static <E> Iterator<E> mutableIterator(BooleanSupplier hasNext, Supplier<E> next, Runnable remove) { Objects.requireNonNull(hasNext, "hasNext"); Objects.requireNonNull(next, "next"); Objects.requireNonNull(remove, "remove"); class MutableLambdaIterator extends MutableIterator<E> { @Override public boolean hasNext() { return hasNext.getAsBoolean(); } @Override protected E nextElement() { return next.get(); } @Override protected void removeElement() { remove.run(); } } return new MutableLambdaIterator(); } /** * Creates an {@link java.util.Iterator} checked has an internal count of how many times it has been called. * The current index1 is passed to the lambda expressions. * * @param hasNext used to implement {@link java.util.Iterator#hasNext()} * @param next used to implement {@link java.util.Iterator#next()} * @param <E> the generic type * @return a new instance */ public static <E> Iterator<E> indexIterator(IntPredicate hasNext, IntFunction<E> next) { Objects.requireNonNull(hasNext, "hasNext"); Objects.requireNonNull(next, "next"); class IndexIterator extends BaseIterator<E> { private int index; @Override public boolean hasNext() { return hasNext.test(index); } @Override protected E nextElement() { return next.apply(index++); } } return new IndexIterator(); } /** * As {@link #indexIterator(java.util.function.IntPredicate, java.util.function.IntFunction)} * except with a remove method. * * @param hasNext used to implement {@link java.util.Iterator#hasNext()} * @param next used to implement {@link java.util.Iterator#next()} * @param remove used to implement {@link java.util.Iterator#remove()} * @param <E> the generic type * @return a new instance */ public static <E> Iterator<E> mutableIndexIterator(IntPredicate hasNext, IntFunction<E> next, IntConsumer remove) { Objects.requireNonNull(hasNext, "hasNext"); Objects.requireNonNull(next, "next"); Objects.requireNonNull(remove, "remove"); class MutableIndexIterator extends MutableIterator<E> { private int index; @Override public boolean hasNext() { return hasNext.test(index); } @Override protected E nextElement() { return next.apply(index++); } @Override protected void removeElement() { remove.accept(index - 1); } } return new MutableIndexIterator(); } @SafeVarargs public static <E> Iterator<E> arrayIterator(E... elements) { Objects.requireNonNull(elements, "elements"); return indexIterator(i -> i < elements.length, i -> elements[i]); } @SuppressWarnings("unchecked") public static <E> Iterator<E> emptyIterator() { return (Iterator<E>) EMPTY; } @SafeVarargs public static <E> Iterator<E> mutableArrayIterator(IntConsumer remove, E... elements) { Objects.requireNonNull(elements, "elements"); return mutableIndexIterator(i -> i < elements.length, i -> elements[i], remove); } public static <E> Iterator<E> untilIterator(Supplier<? extends E> supplier, Predicate<? super E> until) { Objects.requireNonNull(supplier, "supplier"); Objects.requireNonNull(until, "until"); class UntilIterator extends BaseIterator<E> { private boolean initialized; private E pending; @Override protected E nextElement() { E value = pending; pending = supplier.get(); return value; } @Override public boolean hasNext() { if (!initialized) { initialized = true; pending = supplier.get(); } return until.test(pending); } } return new UntilIterator(); } private static abstract class BaseIterator<E> implements Iterator<E> { @Override public E next() { if (!hasNext()) { throw new NoSuchElementException(); } return nextElement(); } protected abstract E nextElement(); } private static abstract class MutableIterator<E> extends BaseIterator<E> { private boolean canRemove = false; @Override public E next() { E e = super.next(); canRemove = true; return e; } @Override public void remove() { if (canRemove) { canRemove = false; removeElement(); } else { throw new IllegalStateException(); } } protected abstract void removeElement(); } }